﻿'// ========================================================================= '
'// ------------------------------------------------------------------------- '
'//!				\file		CM_Symbols.vb
'			        \date		june 2010
'			        \author		TNick
'
'			        \brief		
'
'
'   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'   This file is considered universal knowledge. No restrictions
'   are imposed; use as you see fit.
'   Please read ReadMe.txt and Licence.txt in root folder
'   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'
'   
'
'// ------------------------------------------------------------------------- '
'// ========================================================================= '
'//
'//
'//
'//
'//  IMPORTS     ------------------------------------------------------------ '
#Region "Imports"

Imports System
Imports Microsoft.Win32

Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.Customization
'Imports Autodesk.AutoCAD.Colors
'Imports Autodesk.AutoCAD.GraphicsSystem

#End Region
'//  IMPORTS     ============================================================ '
'//
'//
'//
'//
'//  DEFINITIONS    --------------------------------------------------------- '
<Assembly: CommandClass(GetType(CM_Symbols))> 


#Region "Public Structures"
    


    '// --------------------------------------------------------------------- '
    '// defines the settings for creating a grid
    Public Structure SYMBSTG
        Dim sDBPath As String ' location of database
        
        '// the scale of the block
        Dim dScl As Double
        '// the rotation of the block
        Dim dRot As Double
        '// the distance between two consecutive blocks
        Dim dSpan As Double


        '// distance between two consecutive lines on a SlopeTz
        Dim dSTZ_Span As Double
        '// the size of the longer line used to indicate Slope 
        Dim dSTZ_Len As Double

    End Structure
    '// ===================================================================== '


#End Region


'//  DEFINITIONS    ========================================================= '
'//
'//
'//
'//
'//  DATA    ---------------------------------------------------------------- '


'//  DATA    ================================================================ '
'//
'//
'//
'//
'//  CLASS    --------------------------------------------------------------- '
Public Class CM_Symbols
	Inherits CModule


    '// --------------------------------------------------------------------- '
    '// DATA

    #Region "Public Constants"
        '// name as displayed in various places
	    Public Const sAPPNAME As String = "Symbols"
        '// version as displayed in various places
	    Public Const sAPPVER As String = "1.0.0.0"
        '// short description
	    Public sAPPTIP As String

        '// Command. Brings up the settings dialog
        Public Const sCMD_SETTINGS As String = "TNIK_SYM_STG"
        '// Command. Shows dialog for symbol insertion
        Public Const sCMD_INS as String = "TNIK_SYM_INS"
        '// Command. Inserts all symbols in the database
        Public Const sCMD_SLOPE As String = "TNIK_SYM_SLP"
        '// Command. Inserts all symbols in the database
        Public Const sCMD_INALL As String = "TNIK_SYM_INALL"
    #End Region

    '// this is where the settings are stored durring run-time
    Public Shared Stgs As SYMBSTG

    '// ===================================================================== '





#Region "Private general purpose Functions"


    '// --------------------------------------------------------------------- '
    '// This function saves current settings
    Private Shared Sub SaveSett()

        CSett.SaveStg(sAPPNAME, "Stgs.sDBPath", Stgs.sDBPath)

        CSett.SaveStg(sAPPNAME, "Stgs.dScl", Stgs.dScl)
        CSett.SaveStg(sAPPNAME, "Stgs.dRot", Stgs.dRot)
        CSett.SaveStg(sAPPNAME, "Stgs.dSpan", Stgs.dSpan)

        CSett.SaveStg(sAPPNAME, "Stgs.dSTZ_Span", Stgs.dSTZ_Span)
        CSett.SaveStg(sAPPNAME, "Stgs.dSTZ_Len", Stgs.dSTZ_Len)

        GC.Collect()
        GC.WaitForPendingFinalizers()
    End Sub
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
    '// This function loads current settings
    Private Shared Sub GetSett()

        Stgs.sDBPath = CSett.GetStrStg(sAPPNAME, "Stgs.sDBPath", _
                        CApp.sAppPath & "Misc\Symbols.dwg")
        If (Stgs.sDBPath = "") Then
            Stgs.sDBPath = CApp.sAppPath & "Misc\Symbols.dwg"
        End If


        Stgs.dScl = CSett.GetDblStg(sAPPNAME, "Stgs.dScl", _
                        1)
        Stgs.dRot = CSett.GetDblStg(sAPPNAME, "Stgs.dRot", _
                        0)
        Stgs.dSpan = CSett.GetDblStg(sAPPNAME, "Stgs.dSpan", _
                        10)


        Stgs.dSTZ_Span = CSett.GetDblStg(sAPPNAME, "Stgs.dSTZ_Span", _
                        5)
        Stgs.dSTZ_Len = CSett.GetDblStg(sAPPNAME, "Stgs.dSTZ_Len", _
                        10)

        GC.Collect()
        GC.WaitForPendingFinalizers()
    End Sub
    '// ===================================================================== '


    '// --------------------------------------------------------------------- '
    '// This function shows current settings
    Private Shared Function PrintStg(ByRef lcStg As SYMBSTG) As String

        Return ( _
         vbCrLf & CMain._T(TX.CSTG) & sAPPNAME & ": " & vbCrLf & _
          vbTab & CMain._T(TX.SCALE) & " = " & lcStg.dScl.ToString() & vbCrLf & _
          vbTab & CMain._T(TX.ROT) & " = " & lcStg.dRot.ToString() & vbCrLf & _
          vbTab & CMain._T(TX.SPAN) & " = " & lcStg.dSpan.ToString() & vbCrLf & _
          vbTab & CMain._T(TX.DBFPATH) & " = " & lcStg.sDBPath & vbCrLf & _
            vbCrLf & _
          CMain._T(TX.SLOPETLZ) & vbCrLf & _
          vbTab & CMain._T(TX.SPAN) & " = " & lcStg.dSTZ_Span.ToString() & vbCrLf & _
          vbTab & CMain._T(TX.LENGHT) & " = " & lcStg.dSTZ_Len.ToString() & vbCrLf)

    End Function
    '// ===================================================================== '

#End Region


#Region "Common interface" ' -----------------------

    '// --------------------------------------------------------------------- '
	'// a new instance is created
	Public Sub New()
		Try
            sAPPTIP = CMain._T(TX.SYM_INFO)
			Return
		Catch ex As System.Exception
			CMain.DebugException(ex)
			Return
		End Try
	End Sub
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
	'// the module is asked to terminate
	Public Overrides Function Terminate() As Boolean
		Try
			SaveSett()
			Return True
		Catch ex As System.Exception
			CMain.DebugException(ex)
			Return False
		End Try
	End Function
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
	'// the module is asked to tell it's name
	Public Shared Function GetName() As String
		Return sAPPNAME
	End Function
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
	'// the module is asked to tell about itself
	Public Shared Sub GetInfos(ByRef sName As String, ByRef sVer As String, ByRef sTip As String)
		sName = sAPPNAME
		sVer = sAPPVER
		sTip = CMain._T(TX.SYM_INFO)
	End Sub
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
	'// the module is asked to tell about itself
	Public Shared Function GetDescription() As String
        Dim sOut As String = sAPPNAME
        Try
            Dim cIni As New IniWork(CApp.sAppPath & CMain.APPSTG)
            If cIni.HasErrors = True Then Exit Try
            sOut = cIni.Read(sAPPNAME, CMain.DESCRKEY & _
                             CMain.eAppLang.ToString,sAPPNAME)
        Catch ex As System.Exception
            CMain.DebugException(ex)
        End Try
        Return sOut
	End Function
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
	'// the module is informed about application start-up
	Public Shared Sub DoPrereq()
		Try
			' this function is called at application start-up in order to 
			' allow applications to do any prerequisites
			' there is no instance of this class at this time
			GetSett()
		Catch ex As System.Exception
			CMain.DebugException(ex)
		End Try
		Return
	End Sub
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
	'// create the user interface for this module
	Public Shared Sub DoCUI( _
	 ByRef pcs As CustomizationSection, _
	 ByRef mg As MacroGroup)
		' this function is called when a CUI is builded in order to
		' allow any application specifics
		Try
        #If HARDCORE_CUI
            If CApp.cuiCl Is Nothing then Exit Try
            CApp.cuiCl.AddMacro(sCMD_INS,"Sym_Ins")
            CApp.cuiCl.AddMacro(sCMD_SLOPE,"Sym_Tlz")
            CApp.cuiCl.AddMacro(sCMD_INALL,"Sym_InsAll")
            CApp.cuiCl.AddMacro(sCMD_SETTINGS,"Sym_Settings")

            CApp.cuiCl.AddToolbar( _
                sAPPNAME, _
                Application.MainWindow.Location.X, _
                100 + MIDS.SIMB * 30)
            CApp.cuiCl.AddToolbarBtn(CMain._T(tx.BYDIR),sCMD_INS)
            CApp.cuiCl.AddToolbarBtn(CMain._T(tx.SLOPETLZ),sCMD_SLOPE)
            CApp.cuiCl.AddToolbarSep()
            CApp.cuiCl.AddToolbarBtn(CMain._T(tx.BYFIXPT),sCMD_INALL)
            CApp.cuiCl.AddToolbarSep()
            CApp.cuiCl.AddToolbarBtn(CMain._T(tx.SETTINGS),sCMD_SETTINGS)

        #Else

			Dim mm1 As MenuMacro = Nothing
			mm1 = New MenuMacro(mg, sCMD_INALL, "^C^C" & sCMD_INALL, "ID_" & sCMD_INALL)
			mm1 = New MenuMacro(mg, sCMD_INS, "^C^C" & sCMD_INS, "ID_" & sCMD_INS)
			mm1 = New MenuMacro(mg, sCMD_SLOPE, "^C^C" & sCMD_SLOPE, "ID_" & sCMD_SLOPE)
			mm1 = New MenuMacro(mg, sCMD_SETTINGS, "^C^C" & sCMD_SETTINGS, "ID_" & sCMD_SETTINGS)


			Dim tbBtn As ToolbarButton = Nothing
			Dim newTb As Toolbar = New Toolbar(sAPPNAME, pcs.MenuGroup)
			newTb.ElementID = "EID_TNIK_Symb"
			newTb.ToolbarOrient = ToolbarOrient.floating
			newTb.ToolbarVisible = ToolbarVisible.show


			tbBtn = New ToolbarButton(newTb, -1)
			tbBtn.Name = CMain._T(tx.INSERT)
			tbBtn.MacroID = "ID_" & sCMD_INS
			tbBtn = New ToolbarButton(newTb, -1)
			tbBtn.Name = CMain._T(TX.SLOPETLZ)
			tbBtn.MacroID = "ID_" & sCMD_SLOPE

			tbBtn = New ToolbarButton(newTb, -1) ' separator

			tbBtn = New ToolbarButton(newTb, -1)
			tbBtn.Name = CMain._T(tx.INSERTALLSY)
			tbBtn.MacroID = "ID_" & sCMD_INALL


			tbBtn = New ToolbarButton(newTb, -1) ' separator

			tbBtn = New ToolbarButton(newTb, -1)
			tbBtn.Name = CMain._T(tx.SETTINGS)
			tbBtn.MacroID = "ID_" & sCMD_SETTINGS

        #End If

		Catch ex As System.Exception
			CMain.DebugException(ex)
		End Try
        GC.Collect()
        GC.WaitForPendingFinalizers()
	End Sub
    '// ===================================================================== '


#End Region

#Region "Internal base work"

    '// --------------------------------------------------------------------- '
	'// compute medium angles for all points of a polyline
    Private Sub GetPolyMedAng (ByRef acPoly as Polyline, _
            ByRef dPtAry() As Double)
        '// the angles for first and last points are computed
        '// in diffrent ways if the polyline is closed or not

        ReDim dPtAry (0 to acPoly.NumberOfVertices - 1)

        Dim dAng01 As Double
        Dim dAng0N As Double
        Dim dAngNM As Double
        Dim i As Integer
        Dim pt0 As Point2d = acPoly.GetPoint2dAt(0)
        Dim pt1 As Point2d = acPoly.GetPoint2dAt(1)
        Dim ptn As Point2d = acPoly.GetPoint2dAt( _
            acPoly.NumberOfVertices - 1)
        Dim ptm As Point2d = acPoly.GetPoint2dAt( _
            acPoly.NumberOfVertices - 2)
        dAng01 = Math.Atan2(pt1.Y - pt0.Y, pt1.X - pt0.X)
        dAngNM = Math.Atan2(ptm.Y - ptn.Y, ptm.X - ptn.X)

        If acPoly.Closed = True Then
            '// compute the angle in 0
            dAng0N = Math.Atan2(ptN.Y - pt0.Y, ptN.X - pt0.X)
            dPtAry(0) = (dAng01 + dAng0N)/2
            '// compute the angle in n
            dAng0N = dAng0N + Math.PI
            dPtAry(acPoly.NumberOfVertices - 1) = _
                (dAng0N + dAngNM)/2
        Else
            dPtAry(0) = dAng01 + Math.PI/2
            dPtAry(acPoly.NumberOfVertices - 1) = _
                dAngNM + Math.PI/2
        End If
        '//  in this loop dAng01 holds the angle computed
        '// in previous pass and gets it's value 
        '// from dAng0N
        dAng01 = dAng01 + Math.PI
        For i = 1 to acPoly.NumberOfVertices - 2
            '//  pt1 is the point at i
            '//  pt0 is the point at i+1
            '//  dAng0N is angle between i and i+1 (in i)
            pt0 = acPoly.GetPoint2dAt(i + 1)
            dAng0N = Math.Atan2(pt0.Y - pt1.Y, pt0.X - pt1.X)
            dPtAry(i) = (dAng01 + dAng0N)/2
            dAng01 = dAng0N + Math.PI
            pt1 = pt0
        Next i
                

        GC.Collect()
        GC.WaitForPendingFinalizers()
    End Sub
    '// ===================================================================== '


    '// --------------------------------------------------------------------- '
	'// create lines for a segment with specified angles and points
    Private Sub ISTz_Line(ByRef acDoc As Document, _
                          ByRef acTrans As Transaction, _
                          ByRef acBlkModel As BlockTableRecord, _
                          ByVal dSpan As Double, _
                          ByVal dPerc As Double, _
                          ByRef acPoly As Polyline, _
                          ByRef acPCut As Polyline, _
                          ByVal dAng1 As Double, _
                          ByVal dAng2 As Double, _
                          ByRef pt1 As Point2d, _
                          ByRef pt2 As Point2d)

        Dim PtF As FSK_PT
        Dim PtAry As PtMg = Nothing
        Dim acLine As Line
        Dim LnPrp As FSK_LINE = Nothing
        Dim dA1Lim As Double, dA2Lim As Double
        Dim dDifAng as double

        '// this is the line defined by the two points
        Dim LnBase As FSK_LINE = Nothing
        Dim dAngPerp As Double
        CMain.GetLnFromAcadPt2D(LnBase, pt1, pt2)
        If (LnBase.bVert = True) Then
            dAngPerp = 0
        Else
            dAngPerp = Math.Atan(LnBase.m) + Math.PI / 2
        End If


        '// ---------------------------------------------
        '// deal with last line 
        CMain.GetLnFromAcadPt2D(LnPrp, pt2, dAng2)
        CMain.Intersect_LnPoly(LnPrp,acPCut,False,PtAry)
        If CMain.GetClosesPt_Pt(PtAry, _
                            LnPrp.N_1, _
                            LnPrp.E_1, _
                            PtF) = True Then
            '// we're getting the real angle now
            dAng2 = Math.Atan2(PtF.N_1 - pt2.Y, PtF.E_1 - pt2.X)
        End If
        While (dAng2 > Math.PI*2)
            dAng2 = dAng2 - Math.PI*2
        End While
        While (dAng2 < 0)
            dAng2 = dAng2 + Math.PI*2
        End While
        dA2Lim = dAngPerp
        CMain.GetLnFromAcadPt2D(LnPrp, pt2, dA2Lim)
        CMain.Intersect_LnPoly(LnPrp,acPCut,False,PtAry)
        If CMain.GetClosesPt_Pt(PtAry, _
                            LnPrp.N_1, _
                            LnPrp.E_1, _
                            PtF) = True Then
            '// we're getting the real angle now
            dA2Lim = Math.Atan2(PtF.N_1 - pt2.Y, PtF.E_1 - pt2.X)
        End If
        While (dA2Lim > Math.PI*2)
            dA2Lim = dA2Lim - Math.PI*2
        End While
        While (dA2Lim < 0)
            dA2Lim = dA2Lim + Math.PI*2
        End While
        Dim LenOfLast As Double = CMain.GetLnLen( _
            LnPrp.N_1, _
            LnPrp.E_1, _
            PtF.N_1, _
            PtF.E_1)
        '// =============================================

        '// ---------------------------------------------
        '// deal with first line 
        CMain.GetLnFromAcadPt2D(LnPrp, pt1, dAng1)

        CMain.Intersect_LnPoly(LnPrp,acPCut,False,PtAry)
        '// we need to find closest point to first point
        If CMain.GetClosesPt_Pt(PtAry, _
                            LnPrp.N_1, _
                            LnPrp.E_1, _
                            PtF) = False Then

            GoTo FPtOk
        End If
        '// we're getting the real angle now
        dAng1 = Math.Atan2(PtF.N_1 - pt1.Y, PtF.E_1 - pt1.X)

        acLine = New Line( _
            New Point3d(LnPrp.E_1, LnPrp.N_1, acPoly.Elevation), _
            New Point3d(PtF.E_1, PtF.N_1, acPoly.Elevation))

        acLine.SetDatabaseDefaults(acDoc.Database)
	    acBlkModel.AppendEntity(acLine)
	    acTrans.AddNewlyCreatedDBObject(acLine, True)
        FPtOk:
        While (dAng1 > Math.PI*2)
            dAng1 = dAng1 - Math.PI*2
        End While
        While (dAng1 < 0)
            dAng1 = dAng1 + Math.PI*2
        End While
        dA1Lim = dAngPerp
        CMain.GetLnFromAcadPt2D(LnPrp, pt1, dA1Lim)
        CMain.Intersect_LnPoly(LnPrp,acPCut,False,PtAry)
        If CMain.GetClosesPt_Pt(PtAry, _
                            LnPrp.N_1, _
                            LnPrp.E_1, _
                            PtF) = True Then
            '// we're getting the real angle now
            dA1Lim = Math.Atan2(PtF.N_1 - pt1.Y, PtF.E_1 - pt1.X)
        End If
        While (dA1Lim > Math.PI*2)
            dA1Lim = dA1Lim - Math.PI*2
        End While
        While (dA1Lim < 0)
            dA1Lim = dA1Lim + Math.PI*2
        End While
        '// =============================================



        '// compute the number of long lines that are to be generated
        '// and the lenght of segment between two consecutive lines
        Dim dLnL  As Double = CMain.GetLnLen(LnBase)
        Dim dLenSpanN As Double
        Dim dLenSpanE As Double
        Dim iCnt As Integer
        Try
            iCnt = CInt(dLnL / dSpan)
        Catch
            iCnt = Integer.MaxValue
        End Try
        If (iCnt = 0) Then
            iCnt = 1
            If (dLnL < dSpan / 2) Then
                Return
            End If
            dLenSpanN = (pt2.Y - pt1.Y) / 2
            dLenSpanE = (pt2.X - pt1.X) / 2
        Else
            dLenSpanN = (pt2.Y - pt1.Y) / (iCnt + 1)
            dLenSpanE = (pt2.X - pt1.X) / (iCnt + 1)
        End If

        Dim iInf As Integer
        Dim iMid As Integer
        If (iCnt = 1) Then
            iInf = 0
            iMid = 0
        Else
            '// compute the number of elements influenced by each side
            Try
                iInf = CInt((CDbl(iCnt) / 2) * dPerc)
            Catch
                Return
            End Try
            iMid = iCnt - iInf * 2
            If iMid < 0 Then
                iMid = 1
                iInf = iInf - 1
            End If
        End If
        Dim nTmp As Double
        Dim eTmp As Double
        Dim aTmp As Double

        Dim dCrtAng As Double
        Dim dStepAng As Double
        dDifAng = (dA1Lim - dAng1)
        If dDifAng > Math.PI Then
            dDifAng = (Math.PI * 2 - dDifAng)*(-1)
        ElseIf dDifAng < -1*Math.PI Then
            dDifAng = (Math.PI * 2 + dDifAng)
        End If
        dStepAng = dDifAng / (iInf + 1)
        dCrtAng = dAng1 + dStepAng
        Dim dLnL_ As Double
        Dim dPrevAng As Double = dAng1
        '// influenced by first line
        For i As Integer = 0 to iInf-1
            CMain.GetLnFromAcadPt2D(LnPrp, _
                              LnPrp.N_1 + dLenSpanN, _
                              LnPrp.E_1 + dLenSpanE, _
                              dCrtAng)

            CMain.Intersect_LnPoly(LnPrp,acPCut,False,PtAry)
            If CMain.GetClosesPt_Pt(PtAry, _
                                LnPrp.N_1, _
                                LnPrp.E_1, _
                                PtF) = False Then

                GoTo FPtOk2
            End If
            acLine = New Line( _
                New Point3d(LnPrp.E_1, LnPrp.N_1, acPoly.Elevation), _
                New Point3d(PtF.E_1, PtF.N_1, acPoly.Elevation))
            dLnL_ = CMain.GetLnLen(LnPrp.N_1, LnPrp.E_1, PtF.N_1, PtF.E_1)
            acLine.SetDatabaseDefaults(acDoc.Database)
	        acBlkModel.AppendEntity(acLine)
	        acTrans.AddNewlyCreatedDBObject(acLine, True)

            nTmp = LnPrp.N_1-dLenSpanN/2
            eTmp = LnPrp.E_1-dLenSpanE/2
            aTmp = (dCrtAng + dPrevAng)/2
            acLine = New Line( _
                New Point3d( _
                    eTmp, _
                    nTmp, _
                    acPoly.Elevation), _
                New Point3d( _
                    eTmp + Math.Cos(aTmp)*dLnL_/2, _
                    nTmp + Math.Sin(aTmp)*dLnL_/2, _
                    acPoly.Elevation))
            acLine.SetDatabaseDefaults(acDoc.Database)
	        acBlkModel.AppendEntity(acLine)
	        acTrans.AddNewlyCreatedDBObject(acLine, True)

            FPtOk2:
            If dCrtAng > Math.PI*2 Then
                dCrtAng = dCrtAng mod (Math.PI * 2)
            ElseIf dCrtAng < 0 Then
                dCrtAng = (Math.PI * 2 + dCrtAng)
            End If
            dPrevAng = dCrtAng
            dCrtAng = dCrtAng + dStepAng
        Next i

        '// not influenced (in the middle)
        For i As Integer = 0 to iMid-1
            CMain.GetLnFromAcadPt2D(LnPrp, _
                              LnPrp.N_1 + dLenSpanN, _
                              LnPrp.E_1 + dLenSpanE, _
                              dAngPerp)

            CMain.Intersect_LnPoly(LnPrp,acPCut,False,PtAry)
            If CMain.GetClosesPt_Pt(PtAry, _
                                LnPrp.N_1, _
                                LnPrp.E_1, _
                                PtF) = False Then

                GoTo FPtOk3
            End If
            acLine = New Line( _
                New Point3d(LnPrp.E_1, LnPrp.N_1, acPoly.Elevation), _
                New Point3d(PtF.E_1, PtF.N_1, acPoly.Elevation))
            dLnL_ = CMain.GetLnLen(LnPrp.N_1, LnPrp.E_1, PtF.N_1, PtF.E_1)
            acLine.SetDatabaseDefaults(acDoc.Database)
	        acBlkModel.AppendEntity(acLine)
	        acTrans.AddNewlyCreatedDBObject(acLine, True)

            aTmp = Math.Atan2(PtF.N_1 - LnPrp.N_1, PtF.E_1 - LnPrp.E_1)
            While (aTmp > Math.PI*2)
                aTmp = aTmp - Math.PI*2
            End While
            While (aTmp < 0)
                aTmp = aTmp + Math.PI*2
            End While
            nTmp = aTmp
            aTmp = ( aTmp + dPrevAng ) / 2
            dPrevAng = nTmp

            nTmp = LnPrp.N_1-dLenSpanN/2
            eTmp = LnPrp.E_1-dLenSpanE/2
            acLine = New Line( _
                New Point3d( _
                    eTmp, _
                    nTmp, _
                    acPoly.Elevation), _
                New Point3d( _
                    eTmp + Math.Cos(aTmp)*dLnL_/2, _
                    nTmp + Math.Sin(aTmp)*dLnL_/2, _
                    acPoly.Elevation))
            acLine.SetDatabaseDefaults(acDoc.Database)
	        acBlkModel.AppendEntity(acLine)
	        acTrans.AddNewlyCreatedDBObject(acLine, True)

            FPtOk3:
        Next i

        '// influenced by second line
        dDifAng = (dAng2 - dA2Lim)
        If dDifAng > Math.PI Then
            dDifAng = (Math.PI * 2 - dDifAng)*(-1)
        ElseIf dDifAng < -1*Math.PI Then
            dDifAng = (Math.PI * 2 + dDifAng)
        End If
        dStepAng = dDifAng / (iInf + 1)
        dCrtAng = dA2Lim + dStepAng
        Dim bLastOk As Boolean = False
        For i As Integer = 0 to iInf-1
            CMain.GetLnFromAcadPt2D(LnPrp, _
                              LnPrp.N_1 + dLenSpanN, _
                              LnPrp.E_1 + dLenSpanE, _
                              dCrtAng)

            CMain.Intersect_LnPoly(LnPrp,acPCut,False,PtAry)
            If CMain.GetClosesPt_Pt(PtAry, _
                                LnPrp.N_1, _
                                LnPrp.E_1, _
                                PtF) = False Then
                bLastOk = False
                GoTo FPtOk4
            End If
            acLine = New Line( _
                New Point3d(LnPrp.E_1, LnPrp.N_1, acPoly.Elevation), _
                New Point3d(PtF.E_1, PtF.N_1, acPoly.Elevation))
            dLnL_ = CMain.GetLnLen(LnPrp.N_1, LnPrp.E_1, PtF.N_1, PtF.E_1)
            acLine.SetDatabaseDefaults(acDoc.Database)
	        acBlkModel.AppendEntity(acLine)
	        acTrans.AddNewlyCreatedDBObject(acLine, True)


            nTmp = LnPrp.N_1-dLenSpanN/2
            eTmp = LnPrp.E_1-dLenSpanE/2
            aTmp = (dCrtAng + dPrevAng)/2
            acLine = New Line( _
                New Point3d( _
                    eTmp, _
                    nTmp, _
                    acPoly.Elevation), _
                New Point3d( _
                    eTmp + Math.Cos(aTmp)*dLnL_/2, _
                    nTmp + Math.Sin(aTmp)*dLnL_/2, _
                    acPoly.Elevation))

            acLine.SetDatabaseDefaults(acDoc.Database)
	        acBlkModel.AppendEntity(acLine)
	        acTrans.AddNewlyCreatedDBObject(acLine, True)

            bLastOk = True
            FPtOk4:
            If dCrtAng > Math.PI*2 Then
                dCrtAng = dCrtAng mod (Math.PI * 2)
            ElseIf dCrtAng < 0 Then
                dCrtAng = (Math.PI * 2 + dCrtAng)
            End If
            dPrevAng = dCrtAng
            dCrtAng = dCrtAng + dStepAng
        Next i

        '// there is one more short line left
        If ( bLastOk = True ) Then

            nTmp = LnPrp.N_1+dLenSpanN/2
            eTmp = LnPrp.E_1+dLenSpanE/2
            aTmp = (dCrtAng + dPrevAng)/2
            acLine = New Line( _
                New Point3d( _
                    eTmp, _
                    nTmp, _
                    acPoly.Elevation), _
                New Point3d( _
                    eTmp + Math.Cos(aTmp)*dLnL_/2, _
                    nTmp + Math.Sin(aTmp)*dLnL_/2, _
                    acPoly.Elevation))

            acLine.SetDatabaseDefaults(acDoc.Database)
	        acBlkModel.AppendEntity(acLine)
	        acTrans.AddNewlyCreatedDBObject(acLine, True)
        End If

        GC.Collect()
        GC.WaitForPendingFinalizers()
    End Sub
    '// ===================================================================== '

#End Region


#Region "C O M M A N D S"


    '// --------------------------------------------------------------------- '
	'// display settings dialog
	<CommandMethod(sCMD_SETTINGS)> _
	Public Sub Show_Settings()
		Try
            Dim StgD As CST_Symbols = New CST_Symbols
            Application.ShowModelessDialog(StgD)
		Catch ex As System.Exception
            CMain.PopUpExc()
			CMain.DebugException(ex)
		End Try
        GC.Collect()
        GC.WaitForPendingFinalizers()
	End Sub
    '// ===================================================================== '


    '// --------------------------------------------------------------------- '
	'// display insertion dialog
	<CommandMethod(sCMD_INS)> _
	Public Sub Show_InsDialog()
		Try
            Dim StgD As CD_Ins = New CD_Ins
            Application.ShowModelessDialog(StgD)
		Catch ex As System.Exception
            CMain.PopUpExc()
			CMain.DebugException(ex)
		End Try
        GC.Collect()
        GC.WaitForPendingFinalizers()
	End Sub
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
	'// create slope lines
	<CommandMethod(sCMD_SLOPE, CommandFlags.UsePickSet)> _
	Public Sub Show_InsSlopeTlz()
        '// each individual line starts with a short line at half the distance
        '// the line will end in a long line right above the last point


        Dim acDoc As Document = _
            Application.DocumentManager.MdiActiveDocument
        Dim acPoly As Polyline = Nothing
        Dim acPCut As Polyline = Nothing
        'Dim acLine As Line
        Dim bStop As Boolean
                Dim i as Integer = 1


        If (acDoc Is Nothing) Then
            Return
        End If


        Do
            bStop = True
            '' Start a transaction
            Using acTrans As Transaction = _
                acDoc.Database.TransactionManager.StartTransaction()
		    Try
                '// --------------------------------------------------
                '// Get Paper space (is just a block)
                Dim acBlkModel As BlockTableRecord = DirectCast( _
                    acTrans.GetObject( _
                        acDoc.Database.CurrentSpaceId, _
                        OpenMode.ForWrite),  _
                    BlockTableRecord)
                '// \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

                '// select the polyline to enhance
                If CMain.SelectPolyline(acTrans, acDoc, _
                                        acPoly, True, False, _
                                        CMain._T(TX.SELBPOLY)) = False Then
                    Exit Try
                End If
                acDoc.Editor.SetImpliedSelection(Nothing)

                 '// now get a limiting polyline
                If CMain.SelectPolyline(acTrans, acDoc, _
                                        acPCut, True, True, _
                                        CMain._T(TX.SETCUTPOLY)) = False Then
                    Exit Try
                End If


                '// this array holds target angle for each vertex of the polyline
                '// actual angle that will be used may be +/- PI
                Dim dATrg() As Double = Nothing
                GetPolyMedAng(acPoly, dATrg)
                
                For i = 0 to acPoly.NumberOfVertices - 2
                    Call ISTz_Line(acDoc, acTrans, acBlkModel, _
                                   10, 1, _
                                   acPoly, acPCut, _
                                   dATrg(i), dATrg(i+1), _
                                   acPoly.GetPoint2dAt(i), _ 
                                   acPoly.GetPoint2dAt(i+1) )
                Next
                If acPoly.Closed = True Then
                    Call ISTz_Line(acDoc, acTrans, acBlkModel, _
                               10, 1, _
                               acPoly, acPCut, _
                               dATrg(acPoly.NumberOfVertices-1), dATrg(0), _
                               acPoly.GetPoint2dAt(acPoly.NumberOfVertices-1), _ 
                               acPoly.GetPoint2dAt(0) )
                End If

                acTrans.Commit()
                bStop = False
		    Catch ex As System.Exception
                CMain.PopUpExc()
                acTrans.Abort()
			    CMain.DebugException(ex)
		    End Try
            End Using
        Loop Until bStop = True
        GC.Collect()
        GC.WaitForPendingFinalizers()
	End Sub
    '// ===================================================================== '

    '// --------------------------------------------------------------------- '
	'// have the user pick a point and direction and insert all
	<CommandMethod(sCMD_INALL)> _
	Public Sub InsertAllSymbols()

        Dim acSrcDb As Database = Nothing
		Try

            '// see if the database exists
            If System.IO.File.Exists(Stgs.sDBPath) = False Then
                CMain.AlertUser(CMain._T(TX.ERR_FILE) & vbNewLine & _
                                    Stgs.sDBPath)
                Exit Try
            End If


            Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
            If (acDoc Is Nothing) Then Exit Try

            Dim ppo As PromptPointOptions
            Dim ppr As PromptPointResult
            Dim Ln As FSK_LINE

            Dim CntOnLine As Integer

            '// ask for top left point and a direction
            ppo = New PromptPointOptions(vbLf & CMain._T(TX.FPOINT) & ":")
            ppr = acDoc.Editor.GetPoint(ppo)
            If ppr.Status <> PromptStatus.OK Then Exit Try
            Ln.N_1 = ppr.Value.Y
            Ln.E_1 = ppr.Value.X

            ppo.BasePoint = ppr.Value
            ppo.UseBasePoint = True
            ppo.Message = vbLf & CMain._T(TX.SPOINT) & ":"
            Do
                ppr = acDoc.Editor.GetPoint(ppo)
                If ppr.Status <> PromptStatus.OK Then Exit Try
                Ln.N_2 = ppr.Value.Y
                Ln.E_2 = ppr.Value.X

                If Math.Abs(Ln.N_1 - Ln.N_2) > 0.001 Then Exit Do
                If Math.Abs(Ln.E_1 - Ln.E_2) > 0.001 Then Exit Do
                CMain.AlertUser(TX.ERR_PTCLOSE)
            Loop

            Dim dDst as Double = (Ln.E_2 - Ln.E_1)
            If (Math.Abs(dDst) < CMain.MARGIN) Then
                Ln.bVert = True
                Ln.m = 0
                Ln.b = 0
            Else
                Ln.bVert = False
                Ln.m = ((Ln.N_2 - Ln.N_1) / dDst)
                Ln.b = Ln.N_1 - Ln.m * Ln.E_1
            End If

            '// ask for a number of symbols on line
            Dim pdr As Autodesk.AutoCAD.EditorInput.PromptIntegerResult
            Dim pdo As Autodesk.AutoCAD.EditorInput.PromptIntegerOptions
            
            pdo = New PromptIntegerOptions((vbLf & CMain._T(TX.SYMPERLINE) & ":"))
            pdo.AppendKeywordsToMessage = True
            pdo.AllowNegative = False
            pdo.AllowZero = False
            pdo.DefaultValue = 10
            Call pdo.Keywords.Add(CMain._T(TX.ALL))

            pdr = acDoc.Editor.GetInteger(pdo)
            If pdr.Status = PromptStatus.OK Then
                CntOnLine = pdr.Value
            Else If pdr.Status = PromptStatus.Keyword Then
                CntOnLine = Integer.MaxValue
            Else
                Exit Try
            End If



			Dim dm As DocumentCollection = Application.DocumentManager
			Dim ed As Editor = dm.MdiActiveDocument.Editor
			Dim destDb As Database = dm.MdiActiveDocument.Database
			acSrcDb = New Database(False, True)
			Try
				' Read the DWG into a side database
				acSrcDb.ReadDwgFile(Stgs.sDBPath, System.IO.FileShare.Read, True, "")

				' Create a variable to store the list of block identifiers
				Dim blockIds As New ObjectIdCollection()

				Dim tm As Autodesk.AutoCAD.DatabaseServices.TransactionManager = acSrcDb.TransactionManager

				Using myT As Transaction = tm.StartTransaction()
					' Open the block table
					Dim bt As BlockTable = DirectCast(tm.GetObject(acSrcDb.BlockTableId, OpenMode.ForRead, False), BlockTable)

					' Check each block in the block table
					For Each btrId As ObjectId In bt
						Dim btr As BlockTableRecord = DirectCast(tm.GetObject(btrId, OpenMode.ForRead, False), BlockTableRecord)
						' Only add named & non-layout blocks to the copy list
						If Not btr.IsAnonymous AndAlso Not btr.IsLayout Then
							blockIds.Add(btrId)
						End If
						btr.Dispose()
					Next
				End Using
				ed.WriteMessage((vbLf & "Copied " & blockIds.Count.ToString() & " block definitions from ") + Stgs.sDBPath & " to the current drawing.")
				' Copy blocks from source to destination database
				Dim acIdmap As New IdMapping()
				acSrcDb.WblockCloneObjects(blockIds, destDb.BlockTableId, acIdmap, DuplicateRecordCloning.Replace, False)

                 '' Start a transaction
                Using acTrans As Transaction = _
                    acDoc.Database.TransactionManager.StartTransaction()

                    '// get a reference to table of blocks
                    Dim acBlkTbl As BlockTable = DirectCast( _
                            acTrans.GetObject(acDoc.Database.BlockTableId, _
                                              OpenMode.ForRead),  _
                        BlockTable)

                    ' Get Model space (is just a block)
                    Dim acBlkModel As BlockTableRecord = DirectCast( _
                            acTrans.GetObject( _
                            acBlkTbl(BlockTableRecord.ModelSpace), _
                            OpenMode.ForWrite),  _
                        BlockTableRecord)


                    '// loop in generated array and create one instance of each block
                    Dim iOnL As Integer = 0
                    Dim dLnH As Double = 0
                    Dim dInsPtX As Double = Ln.N_1
                    Dim dInsPtY As Double = Ln.E_1
                    Dim dHeight As Double = 10
                    Dim dWidth As Double = 10

					For Each btrId As ObjectId In acBlkTbl
						Dim btr As BlockTableRecord = DirectCast(acTrans.GetObject( _
						    btrId, OpenMode.ForRead, False), BlockTableRecord)
						If Not btr.IsAnonymous AndAlso Not btr.IsLayout Then
                            Dim br As BlockReference = _
                                New BlockReference( _
                                    New Point3d(dInsPtX, dInsPtY, 0), _
                                    btrId)
                            br.SetDatabaseDefaults()
                            br.Rotation = 0
                            ' Add the block reference to Model space
                            acBlkModel.AppendEntity(br)
                            acTrans.AddNewlyCreatedDBObject(br, True)
                            Try
                            dHeight = _
                                br.GeometricExtents.MaxPoint.Y - _
                                br.GeometricExtents.MinPoint.Y

                            dWidth = _
                                br.GeometricExtents.MaxPoint.X - _
                                br.GeometricExtents.MinPoint.X

                            Catch ex As system.Exception
			                    CMain.DebugException(ex)
                            End Try

                            dInsPtX = dInsPtX + dWidth
                            If (dHeight > dLnH) then dLnH = dInsPtX

                            iOnL = iOnL + 1
                            If (iOnL > CntOnLine) Then
                                '// todo : account for angle
                                If (Ln.bVert = True) Then
                                    dInsPtX = Ln.N_1
                                    dInsPtY = dInsPtY + 15 * dLnH / 10 
                                Else
                                    dInsPtX = Ln.N_1
                                    dInsPtY = dInsPtY + 15 * dLnH / 10 
                                End If

                                iOnL = 0
                                dLnH = 0

                            End If
                        End If
                    Next
                    acTrans.Commit()
                End Using


			Catch ex As System.Exception
                CMain.DebugException(ex)
			End Try
			acSrcDb.Dispose()



        EndOfTry:
		Catch ex As System.Exception
            CMain.PopUpExc()
			CMain.DebugException(ex)
        Finally
            If Not acSrcDb Is Nothing Then
                acSrcDb.Dispose()
            End If
            GC.Collect()
            GC.WaitForPendingFinalizers()
		End Try
	End Sub
    '// ===================================================================== '


#End Region






End Class
'//  CLASS    =============================================================== '
'//
'//
'//
'//
'//  FUNCTIONS    ----------------------------------------------------------- '

'//  FUNCTIONS    =========================================================== '
'//
'//
'//
'//
'// ------------------------------------------------------------------------- '
'// ========================================================================= '








'' ''                '// we are ready to create lines along the polyline
'' ''                '// having another polyline cut the longer lines

'' ''CMain.Intersect_LnPoly(




'' ''                acPt2D  = acPoly.GetPoint2dAt(0)
'' ''                dN1 = acPt2D.X
'' ''                dE1 = acPt2D.Y
'' ''                For i as Integer = 1 to acPoly.NumberOfVertices - 1
'' ''                    acPt2D  = acPoly.GetPoint2dAt(0)
'' ''                    dNd = acPt2D.Y - dN1
'' ''                    dEd = acPt2D.X - dE1
'' ''                    If Math.Abs(dNd) < CMain.MARGIN Then
'' ''                    If Math.Abs(dEd) < CMain.MARGIN Then
'' ''                        Continue For
'' ''                    End If
'' ''                    End If
'' ''                    '// this is current line

'' ''                    Dim dCrtSpan As Double
'' ''                    dLLen = Math.Sqrt(dNd*dNd + dEd*dEd)
'' ''                    dLAng = Math.Atan2(dNd, dEd)
'' ''                    If (dLLen < Stgs.dSTZ_Span) Then
'' ''                        iLnCnt = 1
'' ''                        dCrtSpan = dLLen / 2
'' ''                    Else
'' ''                        iLnCnt = Cint(Stgs.dSTZ_Span / dLLen)
'' ''                        dCrtSpan = dLLen / iLnCnt
'' ''                    End If
'' ''                    Dim dNPice As Double = dCrtSpan * Math.Sin(dLAng)
'' ''                    Dim dEPice As Double = dCrtSpan * Math.Cos(dLAng)
'' ''                    Dim dNNow As Double = dN1 + dNPice
'' ''                    Dim dENow As Double = dE1 + dEPice

'' ''                    '// most of the lines will be perpendicualr on base line
'' ''                    For j As Integer = 0 to iLnCnt - 2





'' ''                        '// next short line base point
'' ''                        dNNow = dNNow + dNPice
'' ''                        dENow = dENow + dEPice

'' ''                    Next j
'' ''                    '// last long line will have it's angle 
'' ''                    '// turned to next line, if any

'' ''                    dN1 = acPt2D.X
'' ''                    dE1 = acPt2D.Y
'' ''                Next i

